/*
 * View.h
 *
 *  Created on: 5 Sep 2011
 *      Author: Allan
 */

#ifndef VIEW_H_
#define VIEW_H_

// C++ includes
#include <vector>
using namespace std;

// Eigen includes
#include <Eigen/Core>
using namespace Eigen;

// GeoReact includes
#include "Utilities/Assert.h"
#include "Types.h"

template<typename Vector>
class View
{
public:
	View(Vector& vec, const vector<Index>& idxs);
	
	const unsigned
	Length() const;
	
	const double& 
	operator[](unsigned i) const;
	
	double& 
	operator[](unsigned i);
	
	operator Vector();
	
	View<Vector>& 
	operator=(const Vector& copy);
	
private:
	Vector& vec;
	
	const vector<Index>& idxs;
};

template<typename Vector>
View<Vector>::View(Vector& vec, const vector<Index>& idxs) :
vec(vec), idxs(idxs)
{}

template<typename Vector>
const unsigned View<Vector>::Length() const
{ return idxs.size(); }

template<typename Vector>
const double& View<Vector>::operator[](unsigned i) const
{ return vec[idxs[i]]; }

template<typename Vector>
double& View<Vector>::operator[](unsigned i)
{ return vec[idxs[i]]; }

template<typename Vector>
View<Vector>::operator Vector()
{
	Vector ni(idxs.size()); 
	
	for(unsigned i = 0; i < idxs.size(); ++i)
		ni[i] = vec[idxs[i]];
	
	return ni;
}

template<typename T> const unsigned Length(const vector<T>& vec) { return vec.size(); }
template<typename T> const unsigned Length(const VectorXd& vec) { return vec.rows(); }

template<typename Vector>
View<Vector>& View<Vector>::operator=(const Vector& copy)
{
	Assert(Length(vec) == idxs.size(), "Size of the vector view does not match size of the copy.");
	
	for(unsigned i = 0; i < idxs.size(); ++i)
		vec[idxs[i]] = copy[i];
	
	return *this;
}

#endif /* VIEW_H_ */
